package BehavioralPattern.Interpreter;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;

/**
 * @Classname : InterpreterClient
 * @Description : 测试 解释器模式
 * 行为型——解释器模式
 * 一、模式定义
 *   Given a language, define a representation for its grammar along with an
 *   interpret that uses the representation to interpret sentences in the language.
 *   给定一门语言，定义它的文法的一种表示，并定义一个解释器，该解释器使用该表示来解释语言中的句子。
 *   优点：
 *      简单语法解析器，便于扩展，只需增加非终止符号
 *   缺点：
 *      ① 每个语法可能产生若干非终止符号，语法规则复杂时会产生大量类（类膨胀），不易维护
 *      ② 由于循环和递归调用，一方面调试错误时抽丝剥茧到最小语法单元才能排查出问题，另一方面可能带来运行效率问题
 *   注意：
 *      ① 尽量不要在重要或复杂模块使用解析器模式，可能会带来难以维护问题
 *      ② 在项目中尽量使用shell、JRuby、Groovy等脚本语言来代替解释器模式
 *      ③ 数学表达式运算建议使用开源解析工具包
 *          MESP（Math Expression String Parser）：http://sourceforge.net/projects/expression-tree/
 *          Expression4J：http://sourceforge.net/projects/expression4j/
 * 二、模式类图
 *    https://kdocs.cn/l/cqRQslkS9SEj
 * 三、适用场景
 *   1、当问题重复发生 或 简单语法需要解释时
 * 四、应用举例
 *   1、数学表达式运算
 *   2、SQL语法解析
 *   3、正则表达式解析
 *   4、开发一种新的语言
 * @Author : chentianyu
 * @Date 2023/3/10 07:29
 */


public class InterpreterClient {
    public static void main(String[] args) throws IOException {
        // 获取表达式
        String expStr = getExpStr();
        // 获取参数
        Map<String, Integer> map = getMap(expStr);
        // 创建解析器
        Caculator caculator = new Caculator(expStr);
        // 运算
        int result = caculator.run(map);
        System.out.println("运算结果为：" + expStr + "=" + result);
    }

    /**
     * 键盘输入获取表达式
     *
     * @return
     * @throws IOException
     */
    public static String getExpStr() throws IOException {
        System.out.print("请输入表达式：");
        return (new BufferedReader(new InputStreamReader(System.in))).readLine();
    }

    /**
     * 键盘输入获取参数值映射
     *
     * @param expStr
     * @return
     * @throws IOException
     */
    public static Map<String, Integer> getMap(String expStr) throws IOException {
        Map<String, Integer> map = new HashMap<>();
        // 解析有几个参数需要映射
        for (char c : expStr.toCharArray()) {
            if (c != '+' && c != '-') {
                // 避免出现重复参数
                if (!map.containsKey(String.valueOf(c))) {
                    System.out.print("请输入参数" + c + "的值：");
                    String in = (new BufferedReader(new InputStreamReader(System.in))).readLine();
                    map.put(String.valueOf(c), Integer.valueOf(in));
                }
            }
        }
        return map;
    }

}

/** 20220310
 * 请输入表达式：a+b-c
 * 请输入参数a的值：3
 * 请输入参数b的值：6
 * 请输入参数c的值：1
 * 运算结果为：a+b-c=8
 */
